# coding=utf-8
import json
import logging
from datetime import datetime

import requests

from async import async_job
from common.lottery import OPENCAI_API_URL, OPENCAI_LOTTERY_TYPES, LOTTERY_TYPE
from common.lottery.cyclical import TRACK_STATUS
from common.lottery.cyclical.abstract.activity import fullfill_result, \
    get_latest_unpublished_date
from common.lottery.cyclical.abstract.order import OrderPayer
from common.lottery.db import create_track_index
from common.timer import TimerEvent, TIMER_EVENT_TYPE
from common.utils import exceptions as err, tz
from common.utils.exceptions import CrawlerError
from common.utils.id_generator import generate_long_id

_LOGGER = logging.getLogger('bigbang')


def smart_track_handler(user_id, activity_type, info, smart_track, lottery_logic):
    info['user_id'] = user_id
    track_id = generate_long_id('track_id')
    order_payer = OrderPayer(activity_type)
    has_order = False
    succ_count, succ_amount, tracked_count, tracked_amount = 0, 0, 0, 0
    for each in smart_track:
        info['track_id'] = track_id
        info['term'], info['times'] = each['term'], each['times']
        info['price'] = lottery_logic.calc_total_price(
            info['bet_type'], info['number'], info['times'], info['unit'])
        if info['price'] <= 0:
            continue
        try:
            order = order_payer.pay(info)
            if order:
                has_order = True
                succ_count += 1
                succ_amount += order.price
                if order.track_status == TRACK_STATUS.TRACKED:
                    tracked_count += 1
                    tracked_amount += order.price
        except err.TermExpired:
            # 对于追号，如果已经开了，就跳过这一期
            pass
        except Exception as e:
            _LOGGER.exception('smart track error, %s, %s', locals(), str(e))
    if has_order:
        create_track_index(activity_type, user_id, track_id,
                           succ_count, succ_amount, tracked_count, tracked_amount)
        async_job.generate_track_detail(track_id)
    return succ_count, succ_amount


def crawl_from_opencai(lottery_type):
    unpublished_date = get_latest_unpublished_date(lottery_type)
    if not unpublished_date:
        logging.debug(u'no unpublished term for %s' % OPENCAI_LOTTERY_TYPES.get(lottery_type))
        return
    logging.info(u'crawling %s <%s>' % (OPENCAI_LOTTERY_TYPES.get(lottery_type), unpublished_date))
    url = OPENCAI_API_URL % (OPENCAI_LOTTERY_TYPES.get(lottery_type), unpublished_date.strftime('%Y-%m-%d'))
    response = requests.get(url, timeout=10)
    if response.status_code != 200:
        raise CrawlerError('opencai api not return 200. status code: %s' % response.status_code)
    _parse_and_fill_opencai(json.loads(response.text), url, lottery_type)


def _validate_phase(lottery_type, phase):
    if lottery_type in (LOTTERY_TYPE.CQ_SSC, LOTTERY_TYPE.TJ_SSC, LOTTERY_TYPE.XJ_SSC):
        if len(phase) != 11:
            return False
        date = phase[:8]
        term = phase[-3:]
        try:
            datetime.strptime(date, '%Y%m%d')
        except ValueError:
            return False
        if int(term) > 120:
            return False
        return True
    return True


def _validate_number(lottery_type, number):
    if lottery_type in (LOTTERY_TYPE.CQ_SSC, LOTTERY_TYPE.TJ_SSC, LOTTERY_TYPE.XJ_SSC):
        if number.isdigit() and len(number) == 5:
            return True
        else:
            return False
    return True


def _parse_and_fill_opencai(response_data, refer, lottery_type):
    for item in response_data.get('data', []):
        phase = item.get('expect')
        number = item.get('opencode', '').replace(',', '')
        if lottery_type in (LOTTERY_TYPE.SD_11X5, LOTTERY_TYPE.JX_11X5,
                            LOTTERY_TYPE.SH_11X5, LOTTERY_TYPE.GD_11X5, LOTTERY_TYPE.BJ_PK10,):
            number = ','.join([str(int(x)) for x in item.get('opencode', '').split(',')])
        if lottery_type in (LOTTERY_TYPE.CQ_LF,):
            number = item.get('opencode')
        logging.info(u'crawled %s <%s> %s' % (OPENCAI_LOTTERY_TYPES.get(lottery_type), phase, number))
        if _validate_phase(lottery_type, phase) and _validate_number(lottery_type, number):
            activity = fullfill_result(lottery_type, phase, number, refer)
            if activity:
                TimerEvent.submit(TIMER_EVENT_TYPE.CALC_STATS,
                                  {'number': number, 'term': phase, 'activity_type': lottery_type},
                                  tz.now_ts())
                TimerEvent.submit(TIMER_EVENT_TYPE.ACTIVITY_ANNOUNCE,
                                  {'number': number, 'term': phase, 'activity_type': lottery_type},
                                  tz.now_ts())
        else:
            logging.error('%s opencai api phase <%s> or number <%s> invalid' % (
                OPENCAI_LOTTERY_TYPES.get(lottery_type), phase, number))
